/*
@file: basic.cpp
@author: ZZH
@time: 2022-05-05 11:23:33
@info: 基本函数库实现文件
*/
#include "libFun.h"

EXPORT void __sin(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    float* arg0 = static_cast<float*>(pArgs->args[0]);
    for (int i = 0;i < allCalNum;i++)
        output[i] = sin(arg0[i]);
}

EXPORT void __cos(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    float* arg0 = static_cast<float*>(pArgs->args[0]);
    for (int i = 0;i < allCalNum;i++)
        output[i] = cos(arg0[i]);
}

EXPORT void __rand(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;

    srand(time(NULL));
    for (int i = 0;i < allCalNum;i++)
        output[i] = rand();
}

EXPORT void __inner_max(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    float* arg0 = static_cast<float*>(pArgs->args[0]);
    float currentMax = 0;

    for (int i = 0;i < allCalNum;i++)
        currentMax = __max(arg0[i], currentMax);

    for (int i = 0;i < allCalNum;i++)
        output[i] = currentMax;
}

EXPORT void __inner_min(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    float* arg0 = static_cast<float*>(pArgs->args[0]);
    float currentMin = 0;

    for (int i = 0;i < allCalNum;i++)
        currentMin = __min(arg0[i], currentMin);

    for (int i = 0;i < allCalNum;i++)
        output[i] = currentMin;
}

//使用CPU的rdrand指令产生硬件随机数
EXPORT void hrand(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    for (int i = 0;i < allCalNum;i++)
    {
#ifndef ANDROID
        asm volatile("rdrand %0":"=r"(*output));
#else
        output[i] = 0;
#endif
    }
}

EXPORT void __abs(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    float* arg0 = static_cast<float*>(pArgs->args[0]);
    for (int i = 0;i < allCalNum;i++)
        output[i] = fabs(arg0[i]);
}

EXPORT void freq(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    float* arg0 = static_cast<float*>(pArgs->args[0]);

    for (int i = 0;i < allCalNum;i++)
        output[i] = 2 * 3.1415926535 * arg0[i] * pArgs->t[i];
}

EXPORT void length(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    float* arg0 = static_cast<float*>(pArgs->args[0]);
    const int halfCalNum = allCalNum / 2;

    for (int i = 0, j = 0;i < halfCalNum;i++, j += 2)
    {
        output[i] = sqrtf(powf(arg0[j], 2) + powf(arg0[j + 1], 2));
        output[i + halfCalNum] = 0;
    }
}

EXPORT void angle(pFunCallArg_t pArgs, float* output)
{

}

EXPORT void conv(pFunCallArg_t pArgs, float* output)
{
    float* arg0 = static_cast<float*>(pArgs->args[0]);
    uint32_t len0 = abs(*static_cast<float*>(pArgs->args[0]));
    float* arg1 = static_cast<float*>(pArgs->args[0]);
    uint32_t len1 = abs(*static_cast<float*>(pArgs->args[0]));

    float* buf = new float[len0 + len1];
    memset(buf, 0, len0 + len1);
    memset(output, 0, pArgs->allCalNum);
    buf += len1;
    memcpy(buf, arg0, sizeof(float) * len0);

    for (uint32_t i = 0;i < len0;i++)
    {
        float sum = 0;
        for (uint32_t j = 0;j < len1;j++)
            sum += buf[i - j] * arg1[j];
        output[i] = sum;
    }

    buf -= len1;
    delete[] buf;
}

EXPORT void sum(pFunCallArg_t pArgs, float* output)
{
    int allCalNum = pArgs->allCalNum;
    float* arg0 = static_cast<float*>(pArgs->args[0]);

    // output[0] = arg0[0];

    // for (int i = 1;i < allCalNum;i++)
    //     output[i] = output[i - 1] + arg0[i];

    float res = 0;
    for (int i = 0;i < allCalNum;i++)
        res += arg0[i];

    for (int i = 0;i < allCalNum; i++)
        output[i] = res;
}

LibFunction_t funcs[] = {
    LIB_FUNCTION(__sin, 1, .name = "sin"),
    LIB_FUNCTION(__cos, 1, .name = "cos"),
    LIB_FUNCTION(__rand, 0, .name = "rand"),
    LIB_FUNCTION(__inner_max, 1, .name = "max"),
    LIB_FUNCTION(__inner_min, 1, .name = "min"),
    LIB_FUNCTION(__abs, 1, .name = "abs"),
    LIB_FUNCTION(hrand, 0),
    LIB_FUNCTION(freq, 1),
    LIB_FUNCTION(length, 1),
    // LIB_FUNCTION(angle, 1),
    LIB_FUNCTION(conv, 4),
    LIB_FUNCTION(sum, 1),
    END_OF_LIB
};

register_function_lib(funcs);
